/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * HipNetNode.h
 * Header file for the HipNetNode class
 * Copyright (C) 2012 Hippy
 * Copyright (C) 2005-2009 Simon Newton
 */

#ifndef PLUGINS_HIPNET_HIPNETNODE_H_
#define PLUGINS_HIPNET_HIPNETNODE_H_

#include <string>
#include <map>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

#include "ola/Callback.h"
#include "ola/DmxBuffer.h"
#include "plugins/hipnet/HipNetPackets.h"
#include "plugins/hipnet/HipNetPlugin.h"


namespace ola {
namespace plugin {
namespace hipnet {

// HipNet node types
typedef enum {
    HIPNET_CONTROLLER = 0x0000,  //  server of data to nodes
    HIPNET_NODE = 0x0001               //  node takes data to/from xlr's
} hipnet_node_type;

enum { HIPNET_MAX_UNIVERSES = 255 };

// shm format for the IPC used to talk 
typedef struct shm_block_t {
  uint32_t   seq;  // incremented for every operation, indicates a change                       
  uint8_t ack;
  hipnet_data_t   data; // hipnet data frame
} shm_block_t;


class HipNetNode {
  public:
    explicit HipNetNode(PluginAdaptor *plugin_adaptor);
    virtual ~HipNetNode();

    bool Start();
    bool Stop();

    void SetName(const std::string &name) { m_node_name = name; }
    void SetUniverse(uint8_t universe) { m_universe = universe; }

    // DMX Receiving methods
    bool SetHandler(uint8_t universe, DmxBuffer *buffer,
                    ola::Callback0<void> *handler);
    bool RemoveHandler(uint8_t universe);

    // control methods
   bool SendHipPing(uint8_t mode = 0x00, uint8_t universe_num = 0x00);
   bool SendHipDMX(uint8_t universe, const ola::DmxBuffer &buffer);
   bool SetRXMode(uint8_t universe);
   bool SetDisablePort(uint8_t universe);
   bool SendHipData(uint8_t universe, const DmxBuffer &buffer);
                             
                    
  private:
    typedef struct {
      DmxBuffer *buffer;
      Callback0<void> *closure;
    } universe_handler;

    HipNetNode(const HipNetNode&);
    HipNetNode& operator=(const HipNetNode&);
    
    void HandlePong(const hipnet_pong_t &pong,
                     ssize_t length);
    void HandleData(const hipnet_data_t &data, ssize_t length,
                    const int universe);
    bool SendData(uint8_t universe,
                     const DmxBuffer &buffer);
    bool SendSetRX(uint8_t universe);
    bool SendDisablePort(uint8_t universe);

    bool SendPing(uint8_t );
    bool SendPacket(const int universe,
                            const hipnet_packet_union_t &packet,
                            unsigned int size);

    bool OpenSHM(void);
    bool PollRX(void);    

    
   // variables ------
    PluginAdaptor *m_plugin_adaptor;
    ola::thread::timeout_id m_timeout_id;
    bool m_running;
    uint8_t m_options;
    uint8_t m_universe;
   
    static const int HIP_XLR_FIRST = 0;
    static const int HIP_XLR_LAST = 3;
 
    shm_block_t  *tx_shm[HIP_XLR_LAST+1]; 
    shm_block_t  *rx_shm[HIP_XLR_LAST+1]; 

    int tx_shmid[HIP_XLR_LAST+1];
    key_t  tx_shmkey[HIP_XLR_LAST+1];

    int rx_shmid[HIP_XLR_LAST+1];
    key_t  rx_shmkey[HIP_XLR_LAST+1];

    std::string m_node_name;
      
    std::map<uint8_t, universe_handler> m_handlers;
   
    static const char NODE_NAME[];
    
    static const uint8_t DEFAULT_OPTIONS = 0;
    static const uint16_t HIPNET_PORT = 44779;
};
}  // hipnet
}  // plugin
}  // ola
#endif  // PLUGINS_HIPNET_HIPNETNODE_H_
